// ============================================================================
// 事件总线
// ============================================================================

import { AppEvent, AppEventListener, EventEmitter as IEventEmitter } from '../../shared/types'

/**
 * 事件总线实现
 * 提供应用内的事件发布和订阅机制
 */
export class EventBus implements IEventEmitter {
  private listeners = new Map<string, Set<AppEventListener>>()
  private onceListeners = new Map<string, Set<AppEventListener>>()
  private maxListeners = 100

  /**
   * 添加事件监听器
   */
  on<T extends AppEvent>(eventType: T['type'], listener: AppEventListener<T>): void {
    this.addListener(eventType, listener as AppEventListener, false)
  }

  /**
   * 添加一次性事件监听器
   */
  once<T extends AppEvent>(eventType: T['type'], listener: AppEventListener<T>): void {
    this.addListener(eventType, listener as AppEventListener, true)
  }

  /**
   * 移除事件监听器
   */
  off<T extends AppEvent>(eventType: T['type'], listener: AppEventListener<T>): void {
    const listeners = this.listeners.get(eventType)
    if (listeners) {
      listeners.delete(listener as AppEventListener)
      if (listeners.size === 0) {
        this.listeners.delete(eventType)
      }
    }

    const onceListeners = this.onceListeners.get(eventType)
    if (onceListeners) {
      onceListeners.delete(listener as AppEventListener)
      if (onceListeners.size === 0) {
        this.onceListeners.delete(eventType)
      }
    }
  }

  /**
   * 发射事件
   */
  emit<T extends AppEvent>(event: T): void {
    const eventType = event.type
    
    // 处理普通监听器
    const listeners = this.listeners.get(eventType)
    if (listeners) {
      for (const listener of listeners) {
        this.safeExecuteListener(listener, event)
      }
    }

    // 处理一次性监听器
    const onceListeners = this.onceListeners.get(eventType)
    if (onceListeners) {
      const listenersToExecute = Array.from(onceListeners)
      this.onceListeners.delete(eventType)
      
      for (const listener of listenersToExecute) {
        this.safeExecuteListener(listener, event)
      }
    }
  }

  /**
   * 移除指定事件类型的所有监听器
   */
  removeAllListeners(eventType?: string): void {
    if (eventType) {
      this.listeners.delete(eventType)
      this.onceListeners.delete(eventType)
    } else {
      this.listeners.clear()
      this.onceListeners.clear()
    }
  }

  /**
   * 获取指定事件类型的监听器数量
   */
  listenerCount(eventType: string): number {
    const regularCount = this.listeners.get(eventType)?.size || 0
    const onceCount = this.onceListeners.get(eventType)?.size || 0
    return regularCount + onceCount
  }

  /**
   * 获取所有事件类型
   */
  eventNames(): string[] {
    const regularEvents = Array.from(this.listeners.keys())
    const onceEvents = Array.from(this.onceListeners.keys())
    return [...new Set([...regularEvents, ...onceEvents])]
  }

  /**
   * 设置最大监听器数量
   */
  setMaxListeners(n: number): void {
    this.maxListeners = n
  }

  /**
   * 获取最大监听器数量
   */
  getMaxListeners(): number {
    return this.maxListeners
  }

  /**
   * 检查是否有指定事件的监听器
   */
  hasListeners(eventType: string): boolean {
    return this.listenerCount(eventType) > 0
  }

  /**
   * 等待指定事件发生
   */
  waitFor<T extends AppEvent>(eventType: T['type'], timeout?: number): Promise<T> {
    return new Promise((resolve, reject) => {
      let timeoutId: NodeJS.Timeout | undefined

      const listener = (event: T) => {
        if (timeoutId) {
          clearTimeout(timeoutId)
        }
        resolve(event)
      }

      this.once(eventType, listener)

      if (timeout) {
        timeoutId = setTimeout(() => {
          this.off(eventType, listener)
          reject(new Error(`Timeout waiting for event: ${eventType}`))
        }, timeout)
      }
    })
  }

  /**
   * 创建事件过滤器
   */
  filter<T extends AppEvent>(
    eventType: T['type'],
    predicate: (event: T) => boolean
  ): EventBus {
    const filteredBus = new EventBus()
    
    this.on(eventType, (event: T) => {
      if (predicate(event)) {
        filteredBus.emit(event)
      }
    })
    
    return filteredBus
  }

  /**
   * 创建事件映射器
   */
  map<T extends AppEvent, U extends AppEvent>(
    eventType: T['type'],
    mapper: (event: T) => U
  ): EventBus {
    const mappedBus = new EventBus()
    
    this.on(eventType, (event: T) => {
      const mappedEvent = mapper(event)
      mappedBus.emit(mappedEvent)
    })
    
    return mappedBus
  }

  /**
   * 添加监听器的私有方法
   */
  private addListener(eventType: string, listener: AppEventListener, once: boolean): void {
    const listenersMap = once ? this.onceListeners : this.listeners
    
    if (!listenersMap.has(eventType)) {
      listenersMap.set(eventType, new Set())
    }
    
    const listeners = listenersMap.get(eventType)!
    
    // 检查监听器数量限制
    if (listeners.size >= this.maxListeners) {
      console.warn(`Maximum listeners (${this.maxListeners}) exceeded for event: ${eventType}`)
    }
    
    listeners.add(listener)
  }

  /**
   * 安全执行监听器
   */
  private safeExecuteListener(listener: AppEventListener, event: AppEvent): void {
    try {
      const result = listener(event)
      
      // 如果监听器返回Promise，处理可能的错误
      if (result && typeof result.catch === 'function') {
        result.catch((error: any) => {
          console.error('Error in async event listener:', error)
        })
      }
    } catch (error) {
      console.error('Error in event listener:', error)
    }
  }
}

/**
 * 事件总线装饰器
 * 用于自动将方法注册为事件监听器
 */
export function EventHandler(eventType: string) {
  return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value
    
    // 在类实例化时注册监听器
    const initMethod = target.constructor.prototype.init || function() {}
    
    target.constructor.prototype.init = function() {
      initMethod.call(this)
      
      if ((this as any).eventBus && typeof (this as any).eventBus.on === 'function') {
        ;(this as any).eventBus.on(eventType, originalMethod.bind(this))
      }
    }
    
    return descriptor
  }
}

/**
 * 事件发射器装饰器
 * 用于自动发射事件
 */
export function EmitEvent(eventType: string, eventFactory?: (result: any, args: any[]) => AppEvent) {
  return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value
    
    descriptor.value = function (...args: any[]) {
      const result = originalMethod.apply(this, args)

      if ((this as any).eventBus && typeof (this as any).eventBus.emit === 'function') {
        const event = eventFactory
          ? eventFactory(result, args)
          : {
              type: eventType,
              timestamp: new Date(),
              source: `${target.constructor.name}.${propertyName}`,
              data: { result, args }
            } as unknown as AppEvent

        ;(this as any).eventBus.emit(event)
      }

      return result
    }
    
    return descriptor
  }
}
